﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace ProgNetComponents.Design.Attributes
{
    /// <summary>
    /// Gets attribute base on property value type
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public abstract class DynamicTypeDependentAttribute : Attribute, IDynamicAttribute
    {
        /// <summary>
        /// Property Name
        /// </summary>
        protected string Property;
        /// <summary>
        /// Types
        /// </summary>
        protected Type[] Types;
        /// <summary>
        /// Creates DynamicTypeDependentAttribute instance
        /// </summary>
        /// <param name="property"></param>
        /// <param name="types"></param>
        protected DynamicTypeDependentAttribute(string property, params Type[] types)
        {
            this.Property = property;
            this.Types = types;
        }

        /// <summary>
        /// Gets real attribute
        /// </summary>
        /// <param name="target"></param>
        /// <returns></returns>
        public Attribute GetRealAttribute(object target)
        {
            object obj = null;
            PropertyInfo pi = target.GetSingleProperty(Property);
            if (pi == null)
            {
                FieldInfo fi = target.GetSingleField(Property);
                if (fi != null)
                    obj = fi.GetValue(target);
            }
            else
            {
                obj = pi.GetValue(target, null);
            }
            if (obj != null)
                return GetAttribute(GetTypesMatch(Types, obj.GetType()));

            return null;
        }
        /// <summary>
        /// Gets iv specified type matches any of defVal
        /// </summary>
        /// <param name="defVal"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        protected virtual bool GetTypesMatch(Type[] defVal, Type type)
        {
            if (defVal != null)
            {
                foreach (Type t in defVal)
                {
                    if (type.IsTypeOf(t))
                        return true;
                }
            }
            return false;
        }
        /// <summary>
        /// Gets real attribute base on valuesMatch
        /// </summary>
        /// <param name="valuesMatch"></param>
        /// <returns></returns>
        protected abstract Attribute GetAttribute(bool valuesMatch);
    }
}
